use Flap qw/-m -s/; #no warnings

my $checked_or_selected = sub{
    my($an, $aa, $ah, $ok) = @_;
    if($ok){
        my $atr;
        ($atr = $ah->{$an}) || push @$aa, $atr = [$an];
        $atr->[1] = qq{="$an"};
    }elsif($ah->{$an}){
        @$aa = grep{ lc($_->[0]) ne $an } @$aa;
    }
};

sub{
    my($c, $htm, $p, $opt) = @_;
    my($r, $pre, $len, $sel, %pv);
    if(ref $htm){
        ($r, $htm) = ($htm, $$htm);
        $$r = '';
    }else{
        $r = \(my $htm = '');
    }
    
    while($htm =~ m%<(input|option|/?select|textarea|!--)%ig){
        $htm =~ /-->/gc ? next : return($$r .= substr($htm, $pre)) if $1 eq '!--';
        my $tag = lc $1;
        next if $tag eq '/select' && !($sel = undef);
        my $pos = pos($htm) - length($1) - 1;
        my(@atr, %atr);
        while($htm =~ /\G\s+([\-\w]+)(\s*=\s*("([^"]*)"|'([^']*)'|\S+))?/gc){
            push @atr, $atr{lc($1)} = [$1, $2, $+];
        }
        my $end = ($htm =~ m%\G(\s*/?>)%gc) ? $1 : next;
        my $nm = $atr{name} && $atr{name}->[2];
        my $pv = ($tag eq 'option') ? ($sel || next) : (exists $p->{$nm} ? $p->{$nm} : next);
        
        if($tag eq 'input'){
            my $t = $atr{type} && lc($atr{type}->[2]);
            if(!$t || $t eq 'text' || $t eq 'hidden' || $t eq 'password'){
                next if $t eq 'password' && (!$opt || !$opt->{password});
                $pv = $pv->[0] if UNIVERSAL::isa($pv, 'ARRAY');
                my $atr;
                ($atr = $atr{value}) || push @atr, $atr = ['value'];
                $atr->[1] = '="'.$c->html_value($pv).'"';
            }elsif($t eq 'checkbox' || $t eq 'radio'){
                $pv = $pv{$nm} ||= {map{ $_ => 1 } UNIVERSAL::isa($pv, 'ARRAY') ? @$pv : $pv};
                my $v = $atr{value} && $atr{value}->[2];
                $checked_or_selected->('checked', \@atr, \%atr, $pv->{$c->html_value2str($v)});
            }
        }elsif($tag eq 'option'){
            my $v = $atr{value} && $atr{value}->[2];
            $v = $1 if !defined($v) && $htm =~ m%\G(?=\s*([^<>]+?)\s*</option\b[^>]*>)%igc;
            $checked_or_selected->('selected', \@atr, \%atr, $pv->{$c->html_value2str($v)});
        }elsif($tag eq 'select'){
            $sel = {map{ $_ => 1 } UNIVERSAL::isa($pv, 'ARRAY') ? @$pv : $pv};
        }elsif($tag eq 'textarea'){
            $pv = $pv->[0] if UNIVERSAL::isa($pv, 'ARRAY');
            $htm =~ m%</textarea\b[^>]*>%ig;
            $end .= $c->html_value($pv).'</textarea>';
        }
        $$r .= substr($htm, $pre, $len) if ($len = $pos - $pre);
        $$r .= "<$tag".join('', map{ " $_->[0]$_->[1]" }@atr).$end;
        $pre = pos($htm);
    }
    $$r .= substr($htm, $pre, $len) if ($len = length($htm) - $pre);
    $$r;
};
